package com.minigame.repository.ext;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.minigame.datastore.DataStoreService;
import com.minigame.entity.CacheEntity;
import com.minigame.exception.GameDataRuntimeException;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Id;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Optional;

public class UniqueCacheRepositoryImpl<T,ID extends Serializable> extends SimpleJpaRepository<T,Serializable> implements IUniqueCacheRepository<T,Serializable> {

    private Method idGetMethod;

    private LoadingCache<ID,CacheEntity<T>> loadingCache;


    public UniqueCacheRepositoryImpl(Class<T> domainClass, EntityManager entityManager) throws NoSuchMethodException {
        super(domainClass, entityManager);

        Field[] fields = domainClass.getDeclaredFields();
        for(Field e : fields){
            Id id = e.getAnnotation(Id.class);
            if(id != null){
                idGetMethod = domainClass.getMethod(buildFieldGetName(e));
            }
        }
        CacheLoader<ID,CacheEntity<T>> cacheLoader = new CacheLoader<ID, CacheEntity<T>>() {
            @Override
            public @Nullable CacheEntity<T> load(ID id) throws Exception {
                Optional<T> optional = findById(id);
                T t = null;
                if(optional.isPresent()){
                    t = optional.get();
                }
                CacheEntity<T> cache = new CacheEntity(t);
                return cache;
            }
        };
        loadingCache = Caffeine.newBuilder().build(cacheLoader);

    }

    private String buildFieldGetName(Field field){
        String fieldName = field.getName();
        return  "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    }

    @Override
    public T cacheLoad(Serializable id) {
        return loadingCache.get((ID) id).getV();
    }

    @Override
    public void cacheInsert(T t) {
        try {
            ID id = (ID) idGetMethod.invoke(t);
            CacheEntity<T> cacheEntity = new CacheEntity<T>(t);
            loadingCache.put(id,cacheEntity);
            DataStoreService.getInstance().cacheInsert(this,id,t);
            //执行插入
        }  catch (Exception e) {
            throw new GameDataRuntimeException(e);
        }

    }

    @Override
    public void cacheUpdate(T t) {
        try {
            ID id = (ID) idGetMethod.invoke(t);
            CacheEntity<T> cacheEntity = loadingCache.get(id);
            //如果为空 则警告
            if(cacheEntity.getV() != null){
                DataStoreService.getInstance().cacheUpdate(this,id,t);
            }
            //执行更新
        }  catch (Exception e) {
            throw new GameDataRuntimeException(e);
        }
    }

    @Override
    public void cacheDelete(T t) {
        try {
            ID id = (ID) idGetMethod.invoke(t);
            CacheEntity<T> cacheEntity = loadingCache.get(id);
            //如果为空 则警告
            if(cacheEntity.getV() != null){
                DataStoreService.getInstance().cacheDelete(this,id,t);
            }
            cacheEntity.setV(null);
            //执行删除
        }  catch (Exception e) {
            throw new GameDataRuntimeException(e);
        }

    }
}
